/**
 * Copyright 2011 AJG van Schie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.googlecode.julius.data.define;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import julius.utilities.CollectionHelper;

import org.apache.log4j.Logger;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

public class TracXMLRpcClient {
    public static Logger log = Logger.getLogger(TracXMLRpcClient.class);

    private final String url;
    private final String username;
    private final String password;

    private final String unlimitedResult = "&max=0";

    public TracXMLRpcClient(final String url, final String username, final String password) {
        super();
        this.url = url;
        this.username = username;
        this.password = password;
    }

    /**
     * @param ticketNr
     *            number of the ticket
     * @return Object[] (string[]) with id, created, estimatedhours, totalhours, remaininghours
     */
    public List<List<String>> getTicketSP(final int ticketNr) {
        return toListOfListOfString((Object[]) runQuery(
                "rpc#rpc.ticket",
                "ticket.queryTickets",
                CollectionHelper.list("id=" + ticketNr + "&col=created|estimatedhours|totalhours|remaininghours|status|summary"
                        + unlimitedResult)));

    }

    /**
     * @param ticketID
     * @return
     */
    public List<List<String>> getTicketChangelog(final int ticketID) {
        return toListOfListOfString((Object[]) runQuery("rpc#rpc.ticket", "ticket.changeLog", CollectionHelper.list(ticketID)));
    }

    /**
     * 
     * @return
     */
    public List<String> getMilestoneList() {
        return toListOfString((Object[]) runQuery("rpc#rpc.ticket.milestone", "ticket.milestone.getAll", CollectionHelper.list()));
    }

    /**
     * getTicketList
     * 
     * @param milestone
     *            show only the tickets connected to this milestone
     * @return
     */
    public List<String> getTicketList(final String milestone) {
        return toListOfString((Object[]) runQuery("rpc#rpc.ticket", "ticket.query",
                CollectionHelper.list("milestone=" + milestone + unlimitedResult)));
    }

    /**
     * getMilestoneInfo
     * 
     * @param name
     *            name of the milestone that the information is requested for
     * @return An Object (HashMap) that contains the following information: description, name, due, completed
     */
    @SuppressWarnings("unchecked")
    public HashMap<String, Object> getMilestoneInfo(final String name) {

        return (HashMap<String, Object>) runQuery("rpc#rpc.ticket.milestone", "ticket.milestone.get", CollectionHelper.list(name));
    }

    private List<String> toListOfString(final Object[] in) {
        List<String> toReturn = CollectionHelper.list();
        for (Object o : CollectionHelper.asCollection(in)) {
            toReturn.add(String.valueOf(o));
        }
        log.info("size: " + toReturn.size());
        return toReturn;
    }

    private List<List<String>> toListOfListOfString(final Object[] in) {
        List<List<String>> toReturn = CollectionHelper.list();
        for (Object o : CollectionHelper.asCollection(in)) {
            List<String> insert = new ArrayList<String>();
            for (Object o2 : (Object[]) o) {
                insert.add(String.valueOf(o2));
            }
            toReturn.add(insert);
        }
        return toReturn;
    }

    private Object runQuery(final String urlExtra, final String method, final List<?> params) {
        Object XMLReturn = null;
        try {
            XmlRpcClient client = makeConnection(url + urlExtra);
            XMLReturn = client.execute(method, params);
        } catch (Exception e) {
            log.error(method + " \n" + e + "\n");
        }
        if (XMLReturn == null) {
            log.error(method + "There is no XML return");
            return XMLReturn;
        } else {
            return XMLReturn;
        }
    }

    private XmlRpcClient makeConnection(final String urlcomplete) throws Exception {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setServerURL(new URL(urlcomplete));

        config.setBasicUserName(username);
        config.setBasicPassword(password);

        XmlRpcClient client = new XmlRpcClient();
        client.setConfig(config);
        return client;
    }

}